1 /* 2 Copyright: Marcelo S. N. Mancini (Hipreme|MrcSnm), 2018 - 2021 3 License: [https://creativecommons.org/licenses/by/4.0/|CC BY-4.0 License]. 4 Authors: Marcelo S. N. Mancini 5 6 Copyright Marcelo S. N. Mancini 2018 - 2021. 7 Distributed under the CC BY-4.0 License. 8 (See accompanying file LICENSE.txt or copy at 9 https://creativecommons.org/licenses/by/4.0/ 10 */ 11 module hip.hiprenderer.backend.gl.glvertex; 12 version(OpenGL): 13 14 import hip.hiprenderer.backend.gl.glrenderer; 15 import hip.error.handler; 16 import hip.util.conv; 17 import hip.config.opts; 18 import hip.hiprenderer.renderer; 19 import hip.hiprenderer.shader; 20 import hip.hiprenderer.vertex; 21 22 23 private int getGLUsage(HipBufferUsage usage) 24 { 25 final switch(usage) with(HipBufferUsage) 26 { 27 case STATIC: 28 return GL_STATIC_DRAW; 29 case DEFAULT: 30 case DYNAMIC: 31 return GL_DYNAMIC_DRAW; 32 } 33 } 34 private int getGLAttributeType(HipAttributeType _t) 35 { 36 final switch(_t) with(HipAttributeType) 37 { 38 case Rgba32: return GL_UNSIGNED_BYTE; 39 case Float: return GL_FLOAT; 40 case Int: return GL_INT; 41 case Uint: return GL_UNSIGNED_INT; 42 case Bool: return GL_BOOL; 43 } 44 } 45 46 private ubyte isGLAttributeNormalized(HipAttributeType _t) 47 { 48 final switch(_t) with(HipAttributeType) 49 { 50 case Rgba32: return GL_TRUE; 51 case Float: return GL_FALSE; 52 case Int: return GL_FALSE; 53 case Uint: return GL_FALSE; 54 case Bool: return GL_FALSE; 55 } 56 } 57 58 59 60 61 class Hip_GL3_VertexBufferObject : IHipVertexBufferImpl 62 { 63 immutable int usage; 64 size_t size; 65 uint vbo; 66 67 private __gshared Hip_GL3_VertexBufferObject boundVbo; 68 69 this(size_t size, HipBufferUsage usage) 70 { 71 this.size = size; 72 this.usage = getGLUsage(usage); 73 glCall(() => glGenBuffers(1, &this.vbo)); 74 } 75 void bind() 76 { 77 if(boundVbo !is this) 78 { 79 glCall(()=>glBindBuffer(GL_ARRAY_BUFFER, this.vbo)); 80 boundVbo = this; 81 } 82 } 83 void unbind() 84 { 85 if(boundVbo is this) 86 { 87 glCall(()=>glBindBuffer(GL_ARRAY_BUFFER, 0)); 88 boundVbo = null; 89 } 90 } 91 void setData(const(void)[] data) 92 { 93 this.size = data.length; 94 this.bind(); 95 glCall(() => glBufferData(GL_ARRAY_BUFFER, data.length, cast(void*)data.ptr, this.usage)); 96 } 97 void updateData(int offset, const(void)[] data) 98 { 99 if(data.length + offset > this.size) 100 { 101 ErrorHandler.assertExit( 102 false, "Tried to set data with size "~to!string(size)~"and offset "~to!string(offset)~ 103 "for vertex buffer with size "~to!string(this.size)); 104 } 105 this.bind(); 106 glCall(() => glBufferSubData(GL_ARRAY_BUFFER, offset, data.length, data.ptr)); 107 } 108 ~this(){glCall(() => glDeleteBuffers(1, &this.vbo));} 109 } 110 class Hip_GL3_IndexBufferObject : IHipIndexBufferImpl 111 { 112 immutable int usage; 113 size_t size; 114 index_t count; 115 uint ebo; 116 117 private __gshared Hip_GL3_IndexBufferObject boundEbo; 118 119 this(index_t count, HipBufferUsage usage) 120 { 121 this.size = index_t.sizeof*count; 122 this.count = count; 123 this.usage = getGLUsage(usage); 124 glCall(() => glGenBuffers(1, &this.ebo)); 125 } 126 void bind() 127 { 128 if(boundEbo !is this) 129 { 130 glCall(() => glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this.ebo)); 131 boundEbo = this; 132 } 133 } 134 void unbind() 135 { 136 if(boundEbo is this) 137 { 138 glCall(() => glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); 139 boundEbo = null; 140 } 141 } 142 void setData(const index_t[] data) 143 { 144 this.count = cast(index_t)data.length; 145 this.size = index_t.sizeof*data.length; 146 this.bind(); 147 glCall(() => glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_t.sizeof*data.length, cast(void*)data.ptr, this.usage)); 148 } 149 void updateData(int offset, const index_t[] data) 150 { 151 ErrorHandler.assertExit((offset+data.length)*index_t.sizeof <= this.size); 152 this.bind(); 153 glCall(() => glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, offset, data.length*index_t.sizeof, cast(void*)data.ptr)); 154 } 155 ~this(){glCall(() => glDeleteBuffers(1, &this.ebo));} 156 } 157 158 //Used as a wrapper 159 class Hip_GL_VertexArrayObject : IHipVertexArrayImpl 160 { 161 import hip.util.data_structures; 162 IHipVertexBufferImpl vbo; 163 IHipIndexBufferImpl ebo; 164 private alias VAOInfo = Pair!(HipVertexAttributeInfo, uint, "info", "stride"); 165 VAOInfo[] vaoInfos; 166 167 bool isWaitingCreation = false; 168 169 private __gshared Hip_GL_VertexArrayObject boundVAO; 170 171 void bind(IHipVertexBufferImpl vbo, IHipIndexBufferImpl ebo) 172 { 173 if(vbo is null) 174 { 175 isWaitingCreation = true; 176 return; 177 } 178 else 179 this.vbo = vbo; 180 if(ebo is null) 181 { 182 isWaitingCreation = true; 183 return; 184 } 185 else 186 this.ebo = ebo; 187 isWaitingCreation = false; 188 if(boundVAO !is this) 189 { 190 vbo.bind(); 191 ebo.bind(); 192 foreach(vao; vaoInfos) 193 { 194 glCall(() => glEnableVertexAttribArray(vao.info.index)); 195 glCall(() => glVertexAttribPointer( 196 vao.info.index, 197 vao.info.count, 198 getGLAttributeType(vao.info.valueType), 199 isGLAttributeNormalized(vao.info.valueType), 200 vao.stride, 201 cast(void*)vao.info.offset 202 )); 203 } 204 boundVAO = this; 205 } 206 } 207 208 void unbind(IHipVertexBufferImpl vbo, IHipIndexBufferImpl ebo) 209 { 210 if(boundVAO is this) 211 { 212 foreach(vao; vaoInfos) 213 { 214 glCall(() => glDisableVertexAttribArray(vao.info.index)); 215 } 216 vbo.unbind(); 217 ebo.unbind(); 218 boundVAO = null; 219 } 220 } 221 222 void setAttributeInfo(ref HipVertexAttributeInfo info, uint stride) 223 { 224 if(info.index + 1 > vaoInfos.length) 225 vaoInfos.length = info.index + 1; 226 vaoInfos[info.index] = VAOInfo(info, stride); 227 } 228 void createInputLayout(Shader s){} 229 } 230 231 version(HipGLUseVertexArray) class Hip_GL3_VertexArrayObject : IHipVertexArrayImpl 232 { 233 uint vao; 234 private __gshared Hip_GL3_VertexArrayObject boundVao; 235 this() 236 { 237 glCall(() => glGenVertexArrays(1, &this.vao)); 238 } 239 void bind(IHipVertexBufferImpl vbo, IHipIndexBufferImpl ebo) 240 { 241 if(boundVao !is this) 242 { 243 glCall(() => glBindVertexArray(this.vao)); 244 boundVao = this; 245 } 246 } 247 void unbind(IHipVertexBufferImpl vbo, IHipIndexBufferImpl ebo) 248 { 249 if(boundVao is this) 250 { 251 glCall(() => glBindVertexArray(0)); 252 boundVao = null; 253 } 254 } 255 void setAttributeInfo(ref HipVertexAttributeInfo info, uint stride) 256 { 257 glCall(() => glVertexAttribPointer( 258 info.index, 259 info.count, 260 getGLAttributeType(info.valueType), 261 isGLAttributeNormalized(info.valueType), 262 stride, 263 cast(void*)info.offset 264 )); 265 glCall(() => glEnableVertexAttribArray(info.index)); 266 } 267 void createInputLayout(Shader s){} 268 ~this(){glCall(() => glDeleteVertexArrays(1, &this.vao));} 269 }